import tkinter as tk
from tkinter import messagebox
import random
import os
from PIL import Image, ImageTk, ImageDraw, ImageFont


class FocusUI:
    def on_close(self):
        """关闭窗口前询问用户是否确认"""
        if messagebox.askokcancel('确认关闭', '确定要关闭窗口吗？'):
            self.root.destroy()

    def __init__(self, root_window, user_config, app_logger):
        """
        初始化 FocusUI 类的实例。

        :param root_window: 主窗口实例
        :param user_config: 用户配置实例
        :param app_logger: 日志记录器实例
        """
        self.timer = None
        self.root = root_window
        self.canvas = tk.Canvas(self.root, width=400, height=500, bg='SystemButtonFace', highlightthickness=0)
        self.canvas.pack()
        self.config = user_config
        self.logger = app_logger
        self.timer_running = False
        self.current_mode = 'focus'
        self.round_count = 0
        self.root.geometry('400x500')
        self.root.resizable(False, False)
        # 初始化实例属性
        self.timer_frame = None
        self.timer_label = None
        self.start_btn = None
        self.pause_btn = None
        self.reset_btn = None
        self.min_var = None
        self.max_var = None
        self.round_label = None
        self.mode_label = None
        self.timer_callback = None
        self.focus_var = tk.StringVar(value=str(self.config.get('focus_duration', 90)))
        self.break_var = tk.StringVar(value=str(self.config.get('break_duration', 20)))
        self.confetti_window = None

        # 绑定关闭窗口事件
        self.root.protocol('WM_DELETE_WINDOW', self.on_close)

        # 创建主界面组件
        self.create_widgets()

    def create_widgets(self):
        """
        创建并布局界面上的所有组件，包括标题、计时显示、控制按钮、设置区域和状态显示等。
        """
        # 移除画布的pack，将组件添加到root窗口
        self.canvas.pack_forget()

        # 标题区域
        title_frame = tk.Frame(self.root)
        title_frame.pack(pady=10)
        self.title_label = tk.Label(title_frame, text='Focus Helper', font=('Arial', 24, 'bold'))
        self.title_label.pack()
        self.subtitle_label = tk.Label(title_frame, text='专注模式', font=('Arial', 12))
        self.subtitle_label.pack()

        # 计时区域
        self.timer_frame = tk.Frame(self.root)
        self.timer_frame.pack(pady=20)
        self.timer_label = tk.Label(self.timer_frame, text='00:00:00', font=('Arial', 48))
        self.timer_label.pack()

        # 控制按钮区域
        control_frame = tk.Frame(self.root)
        control_frame.pack(pady=10)

        self.start_btn = tk.Button(control_frame, text='开始', command=self.start_timer, width=10)
        self.start_btn.pack(side=tk.LEFT, padx=5)
        self.pause_btn = tk.Button(control_frame, text='暂停', command=self.pause_timer, width=10, state=tk.DISABLED)
        self.pause_btn.pack(side=tk.LEFT, padx=5)
        self.reset_btn = tk.Button(control_frame, text='重置', command=self.reset_timer, width=10)
        self.reset_btn.pack(side=tk.LEFT, padx=5)

        # 随机间隔设置区域
        settings_frame = tk.LabelFrame(self.root, text='随机间隔设置(分钟)')
        settings_frame.pack(fill=tk.X, padx=20, pady=10)

        # 最小值设置
        min_frame = tk.Frame(settings_frame)
        min_frame.pack(fill=tk.X, padx=10, pady=5)
        tk.Label(min_frame, text='最小值:').pack(side=tk.LEFT)
        self.min_var = tk.IntVar(value=self.config.get('min_interval', 10))
        self.min_slider = tk.Scale(min_frame, from_=1, to=15, orient=tk.HORIZONTAL, variable=self.min_var)
        self.min_slider.pack(side=tk.LEFT, padx=5)

        # 最大值设置
        max_frame = tk.Frame(settings_frame)
        max_frame.pack(fill=tk.X, padx=10, pady=5)
        tk.Label(max_frame, text='最大值:').pack(side=tk.LEFT)
        self.max_var = tk.IntVar(value=self.config.get('max_interval', 15))
        self.max_slider = tk.Scale(max_frame, from_=1, to=15, orient=tk.HORIZONTAL, variable=self.max_var)
        self.max_slider.pack(side=tk.LEFT, padx=5)

        # 应用设置按钮
        btn_frame = tk.Frame(settings_frame)
        btn_frame.pack(fill=tk.X, padx=10, pady=10)
        tk.Button(btn_frame, text='应用设置', command=self.apply_settings).pack(side=tk.LEFT, padx=5)

        # 将试听按钮保存为实例属性
        self.test_btn = tk.Button(btn_frame, text='试听提示音', command=self.play_alert_sound)
        self.test_btn.pack(side=tk.LEFT, padx=5)

        # 底部状态区域
        status_frame = tk.Frame(self.root)
        status_frame.pack(fill=tk.X, side=tk.BOTTOM, pady=10)
        self.round_label = tk.Label(status_frame, text='第0轮')
        self.round_label.pack(side=tk.LEFT, padx=10)
        self.mode_label = tk.Label(status_frame, text='专注90分钟后休息20分钟，随机提示音提醒短暂休息')
        self.mode_label.pack(side=tk.LEFT, padx=10)

    def start_timer(self):
        """
        启动计时器，禁用开始按钮，启用暂停按钮，并记录日志。
        """
        self.timer_running = True
        self.start_btn.config(state=tk.DISABLED)
        self.pause_btn.config(state=tk.NORMAL)
        if self.timer:
            self.timer.start()
        self.logger.info('Focus session started')

    def pause_timer(self):
        """
        暂停计时器，启用开始按钮，禁用暂停按钮，并记录日志。
        """
        self.timer_running = False
        self.start_btn.config(state=tk.NORMAL)
        self.pause_btn.config(state=tk.DISABLED)
        if self.timer:
            self.timer.pause()
        self.logger.info('Focus session paused')

    def reset_timer(self):
        """
        重置计时器，重置计时显示，启用开始按钮，禁用暂停按钮，并记录日志。
        """
        self.timer_running = False
        self.timer_label.config(text='00:00:00')
        self.start_btn.config(state=tk.NORMAL)
        self.pause_btn.config(state=tk.DISABLED)
        if self.timer:
            self.timer.reset()
        self.logger.info('Timer reset')

    def apply_settings(self):
        """
        应用随机间隔设置，验证输入的最小值和最大值是否合法，若合法则更新配置并保存。
        若输入不合法，弹出错误提示框并记录错误日志。
        """
        try:
            min_val = int(self.min_var.get())
            max_val = int(self.max_var.get())
            if min_val < 1 or min_val > 15:
                raise ValueError('最小值必须在1-15之间')
            if max_val < min_val or max_val > 15:
                raise ValueError('最大值必须大于最小值且不超过15')

            self.config['min_interval'] = min_val
            self.config['max_interval'] = max_val
            self.config.save()
            messagebox.showinfo('设置成功', '随机间隔设置已更新')
            self.logger.info(f'Updated random interval settings: {min_val}-{max_val} minutes')
        except ValueError as e:
            messagebox.showerror('输入错误', str(e))
            self.logger.error(f'Invalid settings: {str(e)}')

    def _play_wav_file(self, show_warning=False):
        """
        播放提示音文件。若文件不存在或播放失败，根据参数决定显示警告或错误提示框，并记录日志。

        :param show_warning: 是否显示警告提示框，默认为 False
        """
        try:
            import winsound
            import os
            sound_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'my_alert.wav')

            if not os.path.exists(sound_path):
                raise FileNotFoundError(f"音频文件不存在: {sound_path}")

            # 使用winsound播放WAV文件
            winsound.PlaySound(sound_path, winsound.SND_FILENAME | winsound.SND_ASYNC)
            self.logger.info(f"成功播放音频: {sound_path}")

        except FileNotFoundError as e:
            self.logger.error(f"音频文件问题: {str(e)}")
            if show_warning:
                messagebox.showwarning('提示', '专注时间结束，但提示音文件不存在！')
            else:
                messagebox.showerror('错误', '无法播放提示音，音频文件不存在')
        except Exception as e:
            self.logger.error(f"播放提示音失败: {str(e)}")
            if show_warning:
                messagebox.showwarning('提示', '专注时间结束! 但提示音播放失败')
            else:
                messagebox.showerror('错误', '无法播放提示音')

    def play_alert_sound(self):
        """
        调用内部方法播放提示音。
        """
        self._play_wav_file()

    def set_mode(self, mode):
        """
        设置当前模式（专注或休息），更新模式标签、副标题和窗口背景色。

        :param mode: 模式名称，'focus' 表示专注模式，其他表示休息模式
        """
        self.current_mode = mode
        if mode == 'focus':
            self.mode_label.config(
                text=f'专注{self.config.get("focus_duration")}分钟后休息{self.config.get("break_duration")}分钟, ，随机提示音提醒短暂休息')
            self.subtitle_label.config(text='专注模式')
            self.title_label.config(text='Focus Helper')
            self.root.config(bg='SystemButtonFace')
        else:
            self.mode_label.config(text=f'休息模式 - {self.config.get("break_duration")}分钟后自动开始专注')
            self.root.config(bg='#fff0f0')
            self.subtitle_label.config(text='20分钟休息')

    def update_round_count(self, round_count):
        """
        更新专注轮次，并更新界面上的轮次显示。

        :param round_count: 新的专注轮次
        """
        self.round_count = round_count
        self.round_label.config(text=f'第{self.round_count}轮')

    def update_timer_display(self, hours, minutes, seconds):
        """
        更新计时器的显示内容。

        :param hours: 剩余小时数
        :param minutes: 剩余分钟数
        :param seconds: 剩余秒数
        """
        time_str = f'{hours:02d}:{minutes:02d}:{seconds:02d}'
        self.timer_label.config(text=time_str)

    def set_timer(self, timer):
        """
        设置计时器实例，并为计时器设置提醒和完成回调函数。

        :param timer: 计时器实例
        """
        self.timer = timer
        self.timer.set_reminder_callback(self.trigger_alert)
        self.timer.set_completion_callback(self.handle_completion)

    def handle_completion(self, mode):
        """
        处理计时完成事件，设置当前模式，更新轮次显示，播放提示音，若为休息模式则显示撒花动画。

        :param mode: 当前完成的模式
        """
        self.set_mode(mode)
        self.update_round_count(self.timer.get_round_count())
        self._play_wav_file(show_warning=True)
        if self.confetti_window:
            self.confetti_window.destroy()
        if mode == 'break':
            self.show_confetti_window()

    def show_confetti_window(self):
        """
        创建新窗口并显示撒花动画。
        """
        self.confetti_window = tk.Toplevel(self.root)
        self.confetti_window.title('撒花庆祝')
        self.confetti_window.geometry('400x500')
        self.confetti_window.resizable(False, False)
        
        canvas = tk.Canvas(self.confetti_window, width=400, height=500, bg='white')
        canvas.pack()
        self.show_confetti(canvas)

    def show_confetti(self, canvas):
        """
        在指定画布上显示撒花emoji动画。

        :param canvas: 用于绘制动画的画布
        """
        self.confetti_items = []
        self.confetti_images = []
        self.confetti_sizes = []
        import random
        emojis = ["🎉", "🎊", "🥳"]
        for _ in range(20):
            # 生成更分散的初始位置
            cols = 10
            x = random.randint(0, 800 // cols) + (800 // cols) * random.randint(0, cols - 1)
            y = random.randint(-100, 0)
            emoji = random.choice(emojis)
            size = random.randint(20, 30)
            # 创建一个新的图像用于渲染emoji
            img = Image.new('RGBA', (size * 2, size * 2), (0, 0, 0, 0))
            draw = ImageDraw.Draw(img)
            try:
                font_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'seguiemj.ttf')
                font = ImageFont.truetype(font_path, size)
            except IOError as e:
                self.logger.error(f'Failed to load emoji font: {str(e)}. Using default font.')
                import tkinter.messagebox
                tkinter.messagebox.showwarning('字体缺失', '未找到 seguiemj.ttf 字体文件，已使用默认字体，可能导致撒花动画无法正常显示，请将字体文件放置在与 ui.py 相同目录下。')
                font = ImageFont.load_default()
            draw.text((size, size), emoji, font=font, fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)), anchor='mm')
            photo = ImageTk.PhotoImage(img)
            self.confetti_images.append(photo)
            item = canvas.create_image(x, y, image=photo)
            self.confetti_items.append(item)
            self.confetti_sizes.append(size)
        self.animate_confetti(canvas)

    def animate_confetti(self, canvas):
        """
        实现撒花emoji的动画效果。

        :param canvas: 用于绘制动画的画布
        """
        emojis = ["🎉", "🎊", "🥳"]
        for idx, item in enumerate(self.confetti_items):
            # 引入更丰富的运动模式
            motion_type = random.choice(['float', 'fall', 'swirl'])
            if motion_type == 'float':
                dx = random.randint(-1, 1)
                dy = random.randint(2, 3)
            elif motion_type == 'fall':
                dx = random.randint(-2, 2)
                dy = random.randint(4, 6)
            else:  # swirl
                dx = random.randint(-3, 3) * (1 if random.random() > 0.5 else -1)
                dy = random.randint(2, 3)
            canvas.move(item, dx, dy)
            x, y = canvas.coords(item)
            if y > 1000:
                # 生成更分散的重置位置
                cols = 10
                canvas.coords(item, random.randint(0, 800 // cols) + (800 // cols) * random.randint(0, cols - 1), random.randint(-100, 0))
        # 进一步缩短间隔，提升动画丝滑度和更新速度
        canvas.after(20, lambda: self.animate_confetti(canvas))

    def set_timer_callback(self, callback):
        """
        设置计时器回调函数。

        :param callback: 回调函数
        """
        self.timer_callback = callback

    def trigger_alert(self, mode=None):
        """
        触发计时提醒，记录日志并播放提示音。

        :param mode: 当前模式，默认为 None
        """
        self.logger.info('Timer alert triggered')
        self._play_wav_file(show_warning=True)


class SettingsPanel:
    def __init__(self, parent_window, user_config, user_logger):
        """
        初始化 SettingsPanel 类的实例。

        :param parent_window: 父窗口实例
        :param user_config: 用户配置实例
        :param user_logger: 日志记录器实例
        """
        self.parent = parent_window
        self.config = user_config
        self.logger = user_logger
        self.focus_var = tk.StringVar(value=str(self.config.get('focus_duration', 90)))
        self.break_var = tk.StringVar(value=str(self.config.get('break_duration', 20)))
        self.panel = None

    def create_panel(self):
        """
        创建设置面板窗口，包含专注时长、休息时长设置和保存按钮。

        :return: 设置面板窗口实例
        """
        panel = tk.Toplevel(self.parent)
        panel.title('设置')
        panel.geometry('300x400')
        panel.resizable(False, False)

        # 专注时长设置
        tk.Label(panel, text='专注时长设置', font=('Arial', 14, 'bold')).pack(pady=10)

        # 专注时间
        focus_frame = tk.Frame(panel)
        focus_frame.pack(fill=tk.X, padx=20, pady=5)
        tk.Label(focus_frame, text='专注时长(分钟):').pack(side=tk.LEFT)
        self.focus_var = tk.StringVar(value=str(self.config.get('focus_duration', 90)))
        tk.Entry(focus_frame, textvariable=self.focus_var, width=5).pack(side=tk.LEFT, padx=5)

        # 休息时间
        break_frame = tk.Frame(panel)
        break_frame.pack(fill=tk.X, padx=20, pady=5)
        tk.Label(break_frame, text='休息时长(分钟):').pack(side=tk.LEFT)
        self.break_var = tk.StringVar(value=str(self.config.get('break_duration', 20)))
        tk.Entry(break_frame, textvariable=self.break_var, width=5).pack(side=tk.LEFT, padx=5)

        # 保存按钮
        save_btn = tk.Button(panel, text='保存设置', command=self.save_settings)
        save_btn.pack(pady=20)

        self.panel = panel
        return panel

    def save_settings(self):
        """
        保存设置面板中的专注时长和休息时长设置，验证输入合法性，若合法则更新配置并保存。
        若输入不合法，弹出错误提示框并记录错误日志。
        """
        try:
            focus_duration = int(self.focus_var.get())
            break_duration = int(self.break_var.get())

            if focus_duration < 10 or focus_duration > 120:
                raise ValueError('专注时长必须在10-120分钟之间')
            if break_duration < 5 or break_duration > 30:
                raise ValueError('休息时长必须在5-30分钟之间')

            self.config['focus_duration'] = focus_duration
            self.config['break_duration'] = break_duration
            self.config.save()

            messagebox.showinfo('设置成功', '所有设置已保存')
            self.logger.info(f'Settings updated: focus={focus_duration}min, break={break_duration}min')
            self.panel.destroy()
        except ValueError as e:
            messagebox.showerror('输入错误', str(e))
            self.logger.error(f'Settings validation failed: {str(e)}')


if __name__ == '__main__':
    # 用于测试UI
    root = tk.Tk()
    root.geometry('600x400')
    config = {'focus_duration': 90, 'break_duration': 20, 'min_interval': 10, 'max_interval': 15}
    import logging

    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    # 添加控制台处理器以便查看日志
    console_handler = logging.StreamHandler()
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)

    app = FocusUI(root, config, logger)
    root.mainloop()
